﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Data.Common;
using System.Runtime.Remoting.Messaging;
using System.Data;
using BrightFrame.Aop;

namespace BrightFrame
{
    public class DbProvider
    {
        private static DbConnection _dbConnection;
        private DbCommand _dbCommand;
        private DbDataAdapter _dbDataAdapter;
        private DbProviderFactory _factory;

        private static DbProvider _instance;
        private static readonly object _lockObject = new object();

        public static DbProvider Default
        {
            get {
                lock (_lockObject)
                {
                    if (_instance == null)
                    {
                        _instance = new DbProvider();
                    }
                    else
                    {
                        CallContext.SetData(TransactionAop.ConnectionName, _dbConnection);
                    }
                    return _instance;
                }
            }
        }

        public DbProvider(string config = "Default")
        {
            string connectionString = ConfigurationManager.ConnectionStrings[config].ConnectionString;
            string providerName = ConfigurationManager.ConnectionStrings[config].ProviderName;
            _factory = DbProviderFactories.GetFactory(providerName);
            // 转义 | 为当前程序目录
            connectionString = connectionString.Replace("|", AppDomain.CurrentDomain.BaseDirectory);
            _dbConnection = _factory.CreateConnection();
            if (_dbConnection == null)
                throw new Exception("不能创建数据库连接，请检查数据库配置信息！");
            _dbConnection.ConnectionString = connectionString;
            CallContext.SetData(TransactionAop.ConnectionName, _dbConnection);
        }

        #region [工具操作]
        /// <summary>
        /// 生成参数
        /// </summary>
        /// <param name="name"></param>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public DbParameter CreateParameter(string name, DbType type, object value = null, int size = -1)
        {
            DbParameter parameter = _factory.CreateParameter();
            if (parameter == null)
                throw new Exception("不能创建查询绑定参数，请检查数据库配置信息！");
            parameter.ParameterName = name;
            parameter.DbType = type;
            if (value == null)
                parameter.Value = DBNull.Value;
            else
                parameter.Value = value;
            parameter.Size = size;
            return parameter;
        }

        /// <summary>
        /// 连接装配参数
        /// </summary>
        /// <param name="sql">要查询的语句</param>
        /// <param name="type">要查询的类型</param>
        /// <param name="parameters">绑定的查询参数集合</param>
        private void Link(String sql, CommandType type = CommandType.Text, params DbParameter[] parameters)
        {
            _dbCommand = ((DbConnection)CallContext.GetData(TransactionAop.ConnectionName)).CreateCommand();
            _dbCommand.CommandText = sql;
            _dbCommand.CommandType = type;
            _dbCommand.Parameters.Clear();
            _dbCommand.Parameters.AddRange(parameters);
        }
        #endregion

        /// <summary>
        /// 执行查询，返回受影响的行数，会打开数据连接，注意关闭连接
        /// </summary>
        /// <param name="sql">要执行的语句</param>
        /// <param name="type">要执行的类型</param>
        /// <param name="parameters">查询绑定参数集合</param>
        /// <returns></returns>
        public Int32 ExecuteNonQuery(String sql, CommandType type = CommandType.Text, params DbParameter[] parameters)
        {
            Link(sql, type, parameters);
            return _dbCommand.ExecuteNonQuery();
        }
        /// <summary>
        /// 执行普通SQL语句，返回受影响的行数，会打开数据连接，注意关闭连接
        /// </summary>
        /// <param name="sql">要执行的语句</param>
        /// <param name="parameters">查询绑定参数集合</param>
        /// <returns></returns>
        public Int32 ExecuteNonQuery(String sql, params DbParameter[] parameters)
        {
            return ExecuteNonQuery(sql, CommandType.Text, parameters);
        }
        /// <summary>
        /// 执行查询，返回结果集的首航首列，会打开数据连接，注意关闭连接
        /// </summary>
        /// <param name="sql">执行的查询语句</param>
        /// <param name="type">查询类型</param>
        /// <param name="parameters">查询绑定参数集合</param>
        /// <returns></returns>
        public object ExecuteScalar(String sql, CommandType type = CommandType.Text, params DbParameter[] parameters)
        {
            Link(sql, type, parameters);
            return _dbCommand.ExecuteScalar();
        }
        /// <summary>
        /// 执行查询，返回结果集的首航首列，会打开数据连接，注意关闭连接
        /// </summary>
        /// <typeparam name="T">返回的类型</typeparam>
        /// <param name="sql">执行的查询语句</param>
        /// <param name="parameters">查询绑定参数集合</param>
        /// <returns></returns>
        public object ExecuteScalar(String sql, params DbParameter[] parameters)
        {
            return ExecuteScalar(sql, CommandType.Text, parameters);
        }
        /// <summary>
        /// 执行查询语句并返回DataReader对象，会打开数据连接，注意关闭连接
        /// </summary>
        /// <param name="sql">要执行的查询</param>
        /// <param name="type">查询的类型</param>
        /// <param name="parameters">查询绑定参数集合</param>
        /// <returns></returns>
        public IDataReader ExecuteDataReader(String sql, CommandType type = CommandType.Text, params DbParameter[] parameters)
        {
            Link(sql, type, parameters);
            return _dbCommand.ExecuteReader();
        }
        /// <summary>
        /// 执行查询语句并返回DataReader对象，会打开数据连接，注意关闭连接
        /// </summary>
        /// <param name="sql">要执行的查询</param>
        /// <param name="parameters">查询绑定参数集合</param>
        /// <returns></returns>
        public IDataReader ExecuteDataReader(String sql, params DbParameter[] parameters)
        {
            return ExecuteDataReader(sql, CommandType.Text, parameters);
        }
        /// <summary>
        /// 执行查询返回结果集
        /// </summary>
        /// <param name="sql">要查询的sql语句</param>
        /// <param name="type">查询的类型</param>
        /// <param name="parameters">查询绑定参数集合</param>
        /// <returns></returns>
        public DataSet ExecuteDataSet(String sql, CommandType type = CommandType.Text, params DbParameter[] parameters)
        {
            Link(sql, type, parameters);
            var ds = new DataSet();
            _dbDataAdapter = _factory.CreateDataAdapter();
            _dbDataAdapter.SelectCommand = _dbCommand;
            _dbDataAdapter.Fill(ds);
            return ds;
        }
        /// <summary>
        /// 执行查询返回结果集
        /// </summary>
        /// <param name="sql">要查询的sql语句</param>
        /// <param name="parameters">查询绑定参数集合</param>
        /// <returns></returns>
        public DataSet ExecuteDataSet(String sql, params DbParameter[] parameters)
        {
            return ExecuteDataSet(sql, CommandType.Text, parameters);
        }
        /// <summary>
        /// 执行查询返回结果表
        /// </summary>
        /// <param name="sql">要查询的sql语句</param>
        /// <param name="type">查询的类型</param>
        /// <param name="parameters">查询绑定参数集合</param>
        /// <returns></returns>
        public DataTable ExecuteDataTable(String sql, CommandType type = CommandType.Text, params DbParameter[] parameters)
        {
            Link(sql, type, parameters);
            var dt = new DataTable(sql);
            _dbDataAdapter = _factory.CreateDataAdapter();
            _dbDataAdapter.SelectCommand = _dbCommand;
            _dbDataAdapter.Fill(dt);
            return dt;
        }
        /// <summary>
        /// 执行查询返回结果表
        /// </summary>
        /// <param name="sql">要查询的sql语句</param>
        /// <param name="parameters">查询绑定参数集合</param>
        /// <returns></returns>
        public DataTable ExecuteDataTable(String sql, params DbParameter[] parameters)
        {
            return ExecuteDataTable(sql, CommandType.Text, parameters);
        }
    }
}
